﻿using FySystem.IO;
using FySystem.Net.SimSocket;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace FySystem.Net.LSTP
{
    public class LSTPBase
    {
        public IPAddress IP { get; set; }

        public int Port { get; set; }

        /// <summary>
        /// 收到服务器请求回调
        /// </summary>
        public Action<LSTPRequest, LSTPWebResponse> OnRequestCallback { get; set; }

        #region 文件传输相关
        /// <summary>
        /// 收到文件的第一帧数据时触发，需要接收文件时，除非能确定，否则该回调不应为空，因为为空时会将文件以原本的名字保存到/files/文件夹，存在文件覆写风险
        /// </summary>
        public Func<FileRequest, ReceiveFileConfig> OnBeginReceiveFile { get; set; }

        /// <summary>
        /// 文件接收结束回调
        /// </summary>
        public Action<FileRequest> OnEndReceiveFile { get; set; }
        #endregion

        /// <summary>
        /// 解析请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cSon"></param>
        protected void DecodeRequest(LSTPRequest request,CSon cSon)
        {
            try
            {
                request.RequestId = cSon["requestId"].BytesValue;
                request.Router = cSon["router"].StringValue;
                request.Head = cSon["head"];
                request.MediaType = request.Head["mediaType"];
                request.Body = cSon["body"];
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 判断收到的数据是请求还是返回
        /// </summary>
        /// <param name="cSon"></param>
        /// <returns></returns>
        protected bool IsRequest(CSon cSon)
        {
            bool res = false;
            try
            {
                //根据cSon中是否有router字段来判断是request还是response
                if (cSon.IsContainKey("router"))
                    res = true;
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 创建response并调用回调函数
        /// </summary>
        /// <param name="request"></param>
        /// <param name="bytes"></param>
        /// <exception cref="NotImplementedException"></exception>
        protected void CreateResponseAndCallback(LSTPRequest request, ref List<byte> bytes)
        {
            try
            {
                LSTPWebResponse response = new LSTPWebResponse();
                response.RequestId = request.RequestId;

                //先赋予一个默认值
                response.Status = 0;

                if (request.Router == "/tranfileforinter")
                {
                    //如果是传输文件，则内部处理
                    SaveFile(request, response);
                }
                else
                {
                    //如果是其它
                    OnRequestCallback?.Invoke(request, response);
                }

                //返回数据
                CSon cson = response.ToResponse();
                cson.ToBytesList(ref bytes);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 处理传输过来的文件数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="response"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void SaveFile(LSTPRequest request, LSTPWebResponse response)
        {
            long totalLength = 0;
            long pos = 0;
            string fileId = string.Empty;
            string dfileName = string.Empty;
            string tag = string.Empty;
            try
            {
                totalLength = request.Head["totals"].LongValue.Value;
                pos = request.Head["pos"].LongValue.Value;
                int blockLen = request.Head["length"].IntValue.Value;
                string fullName = request.Head["fullname"].StringValue;
                string fileName = request.Head["filename"].StringValue;
                fileId = request.Head["fileid"].StringValue;
                tag = request.Head["tag"].StringValue;

                dfileName = request.Head["dfilename"].StringValue;       //目标文件名，当收到的数据不是第一帧时，目标文件名由请求端传入，第一帧时为空，由接收端设置并返回请求端

                if (pos == 0)
                {
                    //说明是第一次收到数据
                    ReceiveFileConfig config = null;

                    if (OnBeginReceiveFile != null)
                    {
                        FileRequest fileRequest = new FileRequest();
                        fileRequest.LSTPConnection = request.Connection;
                        fileRequest.TotalLength = totalLength;
                        fileRequest.Position = pos;
                        fileRequest.BlockLength = blockLen;
                        fileRequest.FileName = fileName;
                        fileRequest.Tag = tag;

                        config = OnBeginReceiveFile.Invoke(fileRequest);
                        dfileName = Path.Combine(config.Path, string.IsNullOrWhiteSpace(config.DestName) ? fileName : config.DestName);
                    }
                    else
                    {
                        dfileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "files\\", fileName);
                    }

                    //创建文件
                    FileInfo file = new FileInfo(dfileName);
                    if (file.Directory.Exists == false)
                        file.Directory.Create();
                }

                byte[] data = request.Body.BytesValue;

                //如果收到的是第一帧，且文件已存在，则删除文件后重新创建
                if (pos == 0 && File.Exists(dfileName))
                    File.Delete(dfileName);

                using (FileStream fs = new FileStream(dfileName, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    fs.Position = pos;
                    fs.Write(data, 0, blockLen);
                }

                if (pos + blockLen >= totalLength)
                {
                    //如果文件传输结束，调用回调
                    if (OnEndReceiveFile != null)
                    {
                        OnEndReceiveFile.Invoke(new FileRequest()
                        {
                            LSTPConnection = request.Connection,
                            TotalLength = totalLength,
                            Position = pos,
                            BlockLength = blockLen,
                            FileName = fileName,
                            Tag = tag
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                response.WriteInterError(-2, $"文件传输:{ex.Message}");
            }
            finally
            {
                //创建response
                CSon body = new CSon(CSon.CSonTypes.CObject);
                body.Add("totals", totalLength);
                body.Add("pos", pos);
                body.Add("fileid", fileId);
                body.Add("dfilename", dfileName);
                body.Add("tag", tag);

                response.Body = body;
            }
        }
    }
}
